package icu.twtool.ui.dialog

import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.requiredWidth
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.onClick
import androidx.compose.foundation.window.WindowDraggableArea
import androidx.compose.material.Icon
import androidx.compose.material.LocalTextStyle
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.onKeyEvent
import androidx.compose.ui.input.key.type
import androidx.compose.ui.input.pointer.pointerHoverIcon
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.rememberDialogState
import icu.twtool.entity.Exercise
import icu.twtool.ui.component.ConfirmDialog
import icu.twtool.ui.state.PracticeState
import icu.twtool.ui.state.rememberPracticeState
import icu.twtool.ui.style.MyColors
import icu.twtool.ui.style.MyCursor
import icu.twtool.ui.style.MyShape
import kotlinx.coroutines.delay

/**
 * @author Wen
 * @since 2022-11-04
 */
@OptIn(ExperimentalFoundationApi::class)
@Composable
@Suppress("FunctionName")
fun PracticeDialog(
    exercise: Exercise,
    time: Int = exercise.size * 10,
    onSubmitRequest: (PracticeState) -> Unit
) {
    val practiceDialogState = rememberDialogState(width = 400.dp, height = 300.dp)
    val state = rememberPracticeState(exercise)
    var exitDialog by remember { mutableStateOf(false) }
    val handleExit = {
        exitDialog = true
    }

    Dialog(
        state = practiceDialogState,
        onCloseRequest = handleExit,
        transparent = true,
        undecorated = true,
        resizable = false,
    ) {
        Box(Modifier.fillMaxSize().padding(16.dp)) {
            Surface(
                elevation = 10.dp,
                color = MyColors.SecondaryBackground,
                contentColor = MyColors.OnSecondaryBackground,
                shape = MyShape.RoundedCornerLarge
            ) {
                WindowDraggableArea {
                    Box(Modifier.fillMaxSize().padding(16.dp)) {
                        PracticeBody(state, time)
                        Icon(
                            painterResource("icons/submit.svg"),
                            null,
                            tint = MyColors.Tertiary,
                            modifier = Modifier.size(24.dp).align(Alignment.TopEnd)
                                .pointerHoverIcon(MyCursor.HandCursor).onClick { handleExit() })
                    }
                }
            }
        }

        if (exitDialog) {
            ConfirmDialog("是否提交？", "提交后不可继续编辑",
                onCloseRequest = {
                    exitDialog = false
                }, onConfirmRequest = {
                    while (state.practice.size < state.count) state.practice.add(-1)
                    onSubmitRequest(state)
                }
            )
        }
    }
}

@Composable
@Suppress("FunctionName")
fun PracticeBody(state: PracticeState, time: Int) {
    val countDown by rememberCountDown(state, time)

    val focusRequester = FocusRequester()
    var focused by remember { mutableStateOf(false) }

    Column(Modifier.alpha(if (focused) 1f else 0.6f).onKeyEvent {
        if (it.type == KeyEventType.KeyDown) {
            if (countDown == 0) return@onKeyEvent false
            handleKeyEvent(it.key, state)
        } else {
            false
        }
    }) {
        Box(
            modifier = Modifier.weight(1f).focusRequester(focusRequester).onFocusChanged { focused = it.isFocused }.focusable(),
            contentAlignment = Alignment.Center
        ) {
            CompositionLocalProvider(LocalTextStyle provides MaterialTheme.typography.h4) {
                Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxWidth()) {
                    if (countDown > 0 && state.current < state.count) {
                        Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(16.dp)) {
                            Text(state.first, Modifier.weight(1f), textAlign = TextAlign.Center)
                            Text(state.operation, Modifier.width(32.dp), textAlign = TextAlign.Center)
                            Text(state.second, Modifier.weight(1f), textAlign = TextAlign.Center)
                        }
                        Spacer(Modifier.requiredHeight(8.dp))
                        Text("=", textAlign = TextAlign.Center)
                        Spacer(Modifier.requiredHeight(8.dp))
                        var color = MyColors.Tertiary
                        if (state.error) color = MyColors.Error
                        Text(state.result.ifEmpty { "请输入" }, color = color)
                        if (state.error) {
                            Text("按回车键进入下一题", color = color, fontSize = MaterialTheme.typography.caption.fontSize)
                        }
                    } else {
                        Text("请提交", color = MyColors.Error)
                        Spacer(Modifier.requiredHeight(8.dp))
                        Text("得分：${100 * state.rightCount / state.count}")
                    }
                }
            }
        }
        BottomLayout(countDown, state)

        LaunchedEffect(state) {
            focusRequester.requestFocus()
        }
    }
}

@Composable
@Suppress("FunctionName")
fun BottomLayout(countDown: Int, state: PracticeState) {
    Row(
        Modifier.fillMaxWidth().height(32.dp),
        horizontalArrangement = Arrangement.End,
        verticalAlignment = Alignment.CenterVertically
    ) {
        val yesIcon = painterResource("icons/yes.svg")
        val noIcon = painterResource("icons/no.svg")
        if (countDown > 0) Text("剩余时间：${parseSecond(countDown)}")
        else Text("时间结束", color = MyColors.Error)
        Spacer(Modifier.weight(1f))
        Icon(yesIcon, null, tint = MyColors.Success)
        Spacer(Modifier.requiredWidth(4.dp))
        Text(state.rightCount.toString())
        Spacer(Modifier.requiredWidth(8.dp))
        Icon(noIcon, null, tint = MyColors.Error)
        Spacer(Modifier.requiredWidth(4.dp))
        Text(state.errorCount.toString())
    }
}


@Composable
@Suppress("FunctionName")
private fun rememberCountDown(key: Any, time: Int): MutableState<Int> {
    val state = mutableStateOf(time)
    LaunchedEffect(key) {
        while (state.value > 0) {
            state.value--
            delay(1000)
        }
    }
    return remember { state }
}

private fun parseSecond(second: Int): String {
    return if (second > 60) {
        "${second / 60} 分钟 ${second % 60} 秒"
    } else {
        "$second 秒"
    }
}

@OptIn(ExperimentalComposeUiApi::class)
private fun parseKey(key: Key): Int? {
    return when (key) {
        Key.Zero, Key.NumPad0 -> 0
        Key.One, Key.NumPad1 -> 1
        Key.Two, Key.NumPad2 -> 2
        Key.Three, Key.NumPad3 -> 3
        Key.Four, Key.NumPad4 -> 4
        Key.Five, Key.NumPad5 -> 5
        Key.Six, Key.NumPad6 -> 6
        Key.Seven, Key.NumPad7 -> 7
        Key.Eight, Key.NumPad8 -> 8
        Key.Nine, Key.NumPad9 -> 9

        Key.Backspace -> -1

        Key.Enter, Key.NumPadEnter -> 10

        else -> null
    }
}

private fun handleKeyEvent(key: Key, state: PracticeState): Boolean {
    parseKey(key)?.let { opt ->
        if (state.current >= state.count) return true
        if (state.error) {
            if (opt > 9) {
                state.current++
                state.result = ""
                state.error = false
            }
            return true
        }
        if (opt > 9) {
            if (state.result == "") return true
            val res = state.result == state.answer
            state.practice.add(state.result.toIntOrNull() ?: -1)
            if (res) {
                state.rightCount++
                state.current++
                state.result = ""
            } else {
                state.errorCount++
                state.error = true
            }
        } else {
            if (opt < 0) {
                if (state.result.isNotEmpty()) state.result = state.result.substring(0, state.result.length - 1)
            } else {
                if (state.result.length < 10)
                    state.result += opt
            }
        }
        return true
    }
    return false
}